home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d11
/
ooze.arc
/
OOZE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-12
|
12KB
|
386 lines
/* This program is sort of a lava-lamp for your computer. It requires
VGA equipment or anything else that is compatible with mode 13h of
the VGA (320x200x256 mode). To run the program, execute the command
ooze
The first time this is run, it will generate a random, amorphous
image on the screen and will store this image into the file ooze.ooz.
The image on the screen will then begin to "ooze" all over the
screen. To change the direction of oozing, press a key (like the
space bar). To stop the program and return to DOS, press the Escape
key.
The next time ooze is run, it will read the file ooze.ooz and
proceede directly to ooze the image stored there. Ooze.ooz is mearly
the default filename. Any other filename may be specified on the
command line. If, for instance, the command
ooze image1.ooz
is issued, the file image1.ooz will be read from disk (if it is
present) and the image from this file will be oozed. If image1.ooze
is not found, it will be created in the same manner as ooze.ooz was
created above. But the image created will be different for every new
ooze image file created. You could build a whole library of differnet
ooze files!
---------------------- For Programmers Only -------------------------
This program was translated to Turbo C from Turbo Pascal. The
original TP code was written and copyrighted (1988) by Bret Bulvey
[71330,3567] and can be found in various places as PLASMA.ARC (or
.ZIP depending on where you get it). The translation to TC was done
by me (Jeff Clough [71330,2227]) and includes improvements and
enhancements over the TP code. These include the elimination of
flicker, the use of secondary as well as primary colors in the color
palette, the use of 252 colors instead of only the 191 colors used in
PLASMA, the ability to reverse the direction in which the colors move
on the screen while the program is executing, and being able to
specify the name of the image file to use on the command line. Also,
as a side-effect of the process by which flicker is avoided, OOZE
should run at the same speed on all VGA equipment regardless of the
speed of the computer. The only unique part of the original code
presented here (aside from a few variable and type names) is the
algorithm for generating the amorphous images. The algorithm has been
modified (simplified, actually) so that it includes no floating
point. The original algorithm employed the use of Manhattan distances
to determine how far apart two pixels were. The code presented here
employes its own square root function (using integer bisection) and
uses this to take advantage of a little trick Pathagorus demonstrated
a while back. It is hoped that this new method for computing
distances will produce more rounded edges in the generated images.
Also, there was provision in the original code for adjusting the
"roughness of the image" at compile time. This has been removed
(since it involved a floating point operation).
To eliminate the flicker, it was necessary to implement parts of the
program in assembly language. The code that follows is, therefore, a
hybrid of Turbo C and Assembly. Turbo C 2.0 and TASM were used to
compile/assemble this program. To recompile, do
tcc -B -mc ooze
This will cause TC to "compile" to assembly source code and then
invoke TASM on that code. The -mc switch may optionally be changed to
-ml or -mh for the large or huge memory models, but may not be
changed to -mt, -ms, or -mm because the tiny, small, and medium
memory models all use near data segments. The far data segments used
by the other memory models are necessary because this program uses
the fread and fwrite functions to read from and write to the video
memory directly.
If the identifier "dotest" is defined during compilation, a test
pattern will be generated instead of the more usual amorphous images
when the program is run. This test code was used during debugging to
ensure that all colors were being represented on the screen. If you
change any part of this source code, you may want to use this test
pattern to verify that your changes meet your expectations of them.
To tell the compiler to generate the test code, include the -Ddotest
command line switch when you compile as follows:
tcc -B -mc -Ddotest ooze
When ooze.exe is run, the test pattern will be generated and stored
into whatever file is passed to it on the command line or to ooze.ooz
by default. Don't forget to recompile without the -Ddotest switch so
that the program will once again generate amorphous images.
*/
#if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
#error COMPILE WITH LARGE DATA MODEL.
#endif
#include <bios.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define VERSION "1.1"
typedef struct
{unsigned char r,g,b;
} colortype;
colortype p[256];
int direction=0; /* controls the direction of palette rotation */
void adjust(int x1,int y1,int x,int y,int x2,int y2);
int getpixel(int x,int y);
void putpixel(int x,int y,int c);
void rotatepalette(colortype p[]);
void setvgapalette(void *buffer,int first,int length);
void subdivide(int x1,int y1,int x2,int y2);
unsigned sqrt(long n);
void test(void);
void usage(void);
int main(int argc,char *argv[])
{FILE *file;
char filename[129];
union REGS reg;
unsigned char r,g,b;
int i, /* holds the number of the current palette register */
key, /* holds the scancode of the last key pressed */
newooze; /* TRUE if a new .OOZ file is to be created */
newooze=0;
if (argc>2)
{usage();
return 1;
}
if (argc>1)
{if (stricmp(argv[1],"?")==0 ||
stricmp(argv[1],"-H")==0 ||
stricmp(argv[1],"/H")==0)
{usage();
return 1;
}
strcpy(filename,argv[1]);
}
else
strcpy(filename,"ooze.ooz");
file=fopen(filename,"rb");
if (!file)
{file=fopen(filename,"w+b");
newooze=1;
}
if (!file)
{printf("%s cannot be found or created.\n\n",filename);
usage();
return 2;
}
/* initialize palette register array */
r=53;
g=11;
b=53;
for(i=1;i<=42;i++) /* from magenta to red */
{p[i].r=r;
p[i].g=g;
p[i].b=b--;
}
for(;i<=84;i++) /* from red to yellow */
{p[i].r=r;
p[i].g=++g;
p[i].b=b;
}
for(;i<=126;i++) /* from yellow to green */
{p[i].r=r--;
p[i].g=g;
p[i].b=b;
}
for(;i<=168;i++) /* from green to cyan */
{p[i].r=r;
p[i].g=g;
p[i].b=++b;
}
for(;i<=210;i++) /* from cyan to blue */
{p[i].r=r;
p[i].g=g--;
p[i].b=b;
}
for(;i<=252;i++) /* from blue to magenta */
{p[i].r=++r;
p[i].g=g;
p[i].b=b;
}
/* put VGA into mode 0x13 (320x200x256) */
reg.x.ax=0x13;
int86(0x10,®,®);
setvgapalette(p,0,128);
setvgapalette(&p[128],128,128);
if (newooze)
{
#if defined(dotest)
test();
#else
srand(peek(0x40,0x6c));
putpixel(0,0,random(252)+1);
putpixel(319,0,random(252)+1);
putpixel(319,199,random(252)+1);
putpixel(0,199,random(252)+1);
subdivide(0,0,319,199);
#endif
fwrite(MK_FP(0xa000,0),1,0xfa00,file);
}
else
fread(MK_FP(0xa000,0),1,0xfa00,file);
fclose(file);
/* rotate the palette until the [Esc] key is pressed */
do
{rotatepalette(p);
if (bioskey(1))
{key=bioskey(0)>>8;
direction=1-direction;
}
}
while(key!=1);
/* put VGA into mode 3 (color text mode (80x25)) */
reg.x.ax=3;
int86(0x10,®,®);
return 0;
} /* end of int main(argc,argv[]) */
void adjust(int x1,int y1,int x,int y,int x2,int y2)
{int c,d;
long horz,vert;
if (getpixel(x,y))
return;
horz=(long)(x2-x1);
vert=(long)(y2-y1);
d=sqrt(horz*horz+vert*vert);
if (random(2))
c=((getpixel(x1,y1)+getpixel(x2,y2))/2-random(d)) % 252;
else
c=((getpixel(x1,y1)+getpixel(x2,y2))/2+random(d)) % 252;
if (c<0)
c=-c;
else
if (!c)
c=1;
putpixel(x,y,abs(c));
} /* end of adjust(x1,y1,x,y,x2,y2) */
int getpixel(int x,int y)
{return(peekb(0xa000,320*y+x) & 0xff);
} /* end of int getpixel(x,y) */
void putpixel(int x,int y,int c)
{pokeb(0xa000,320*y+x,c);
} /* end of putpixel(x,y,c) */
void rotatepalette(colortype p[])
{colortype temp;
if (direction)
{memmove(&temp,p+252,sizeof(colortype));
memmove(p+2,p+1,251*sizeof(colortype));
memmove(p+1,&temp,sizeof(colortype));
}
else
{memmove(&temp,p+1,sizeof(colortype));
memmove(p+1,p+2,251*sizeof(colortype));
memmove(p+252,&temp,sizeof(colortype));
}
setvgapalette(p,0,128);
setvgapalette(p+128,128,128);
} /* end of rotatepalette(p) */
void setvgapalette(void *buffer,int first,int length)
{asm cli /* Disable interrupts. */
asm mov dx,3dah
setvgapalette1: /* Wait for vertical retrace to end. */
asm in al,dx
asm test al,8
asm jnz setvgapalette1
setvgapalette2: /* Wait for vertical retrace to start. */
asm in al,dx
asm test al,8
asm jz setvgapalette2
/* Set the VGA palette registers. */
asm push ds
_DS=FP_SEG(buffer);
_SI=FP_OFF(buffer);
asm mov dx,3c8h /* port address of DAC address register. */
asm mov ax,first /* this is the number of first DAC register to update. */
asm out dx,al /* start with this DAC. */
asm inc dx /* 3c9h is the port address where the RGB info is written. */
asm mov cx,length /* this is the number of DAC registers to update. */
setdacloop:
asm mov al,[si]
asm out dx,al
asm inc si
asm mov al,[si]
asm out dx,al
asm inc si
asm mov al,[si]
asm out dx,al
asm inc si
asm loop setdacloop
asm pop ds
asm sti /* Enable interrupts. */
} /* end of setvgapalette(buffer,first,length) */
void subdivide(int x1,int y1,int x2,int y2)
{int c,x,y;
if (bioskey(1))
return;
if (x2-x1<2 && y2-y1<2)
return;
x=(x1+x2)/2;
y=(y1+y2)/2;
adjust(x1,y1,x,y1,x2,y1);
adjust(x2,y1,x2,y,x2,y2);
adjust(x1,y2,x,y2,x2,y2);
adjust(x1,y1,x1,y,x1,y2);
if (getpixel(x,y)==0)
{c=(getpixel(x1,y1)+getpixel(x2,y1)+getpixel(x2,y2)+getpixel(x1,y2))/4;
if (c<1)
c=1;
else
if (c>252)
c=252;
putpixel(x,y,c);
}
subdivide(x1,y1,x,y);
subdivide(x,y1,x2,y);
subdivide(x,y,x2,y2);
subdivide(x1,y,x,y2);
} /* end of subdivide(x1,y1,x2,y2) */
/* Use bisection to find the root of y=x*x-n.
Return the value of x. */
unsigned sqrt(long n)
{long xl,x,xh,y;
if (n<0)
n=-n;
xl=0L; /* (xl,xh) is the range of y=x*x-n */
xh=46340L;
while(xl<xh-1L)
{x=(xl+xh)/2;
y=x*x;
if (y<n)
xl=x;
else
xh=x;
}
if (n-xl*xl < xh*xh-n)
return((int)xl);
else
return((int)xh);
} /* end of unsigned sqrt(n) */
#if defined(dotest)
void test(void)
{int x,y,c;
long h,v;
for(x=0;x<320;x++)
for(y=0;y<200;y++)
{h=(long)(160-x);
v=(long)(199-y);
c=sqrt(h*h+v*v) % 252 + 1;
putpixel(x,y,c);
}
} /* end of test() */
#endif
void usage(void)
{printf("OOZE version %s compiled %s\n\n"
"usage: OOZE [filename]\n"
"where filename is the name of a .OOZ file.\n\n"
"If the file does not exist, it will be created.\n"
"If it already exists, the image in it will be oozed.\n"
"If the filename parameter is not given, a default\n"
"filename of OOZE.OOZ is assumed.\n",VERSION,__DATE__);
} /* end of usage() */